package main;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Vector;

import utils.Debug;
import visualisation.ProcessView;
import XML.XMLProcessGenerator;
import entities.FragmentDirectory;
import entities.MMME;
import entities.MMMEDirectory;
import fragment.AgentState;
import fragment.Fragment;

public class ProcessFinder implements Runnable{
	
	boolean stop = false;
	FragmentDirectory fragDir;
	MMMEDirectory elemDir;
	
	static int nbProcess;
	
	public ProcessFinder(FragmentDirectory fragDir, MMMEDirectory elemDir) {
		super();
		this.fragDir = fragDir;
		this.elemDir = elemDir;
	}

	private static Vector<Fragment> getGeneratingFragments(Vector<Fragment> fragList){
		Vector<Fragment> res = new Vector<Fragment>();
				
		for(Fragment f : fragList){
			if (f.currentState().equals(AgentState.SATISFIED))
				res.add(f);
		}
		return res;
	}
	
	private static HashSet<Fragment> findDependencies(Fragment frag,HashMap<String,MMME> elemList){
		HashSet<Fragment> res = new HashSet<Fragment>();
		for(String s : frag.requiredElements())
			if(elemList.get(s)!= null)
				if(elemList.get(s).getReservationList().contains(frag))
					res.addAll(elemList.get(s).getProducerList());
		return res;
		
	}
	
	private static boolean isLinked(Fragment frag, Fragment ancetrePotentiel, HashMap<Fragment,HashSet<Fragment>> f){
		if (f.get(frag).isEmpty()) return false;
		else if (f.get(frag).contains(ancetrePotentiel) 
					&& (frag.currentProcess() == ancetrePotentiel.currentProcess())	//To check, risk of wrong display
				) return true;
		else{
			boolean res = false;
			for(Fragment e : f.get(frag))
				if(isLinked(e,ancetrePotentiel,f)) res=true;
			return res;
		}
			
	}
	
	private static HashSet<Fragment> suppressedTransitions(HashSet<Fragment> old, HashMap<Fragment,HashSet<Fragment>> f){
		HashSet<Fragment> res=new HashSet<Fragment>();
		for(Fragment fragCourant : old){
			boolean ok =true;
			for(Fragment other : old){
				if(isLinked(other,fragCourant,f)) ok =false;
			}
			if(ok) res.add(fragCourant);
		}
		
		return res;
		
	}
		
	public static void findProcess(FragmentDirectory fragDir, MMMEDirectory elemDir){
		Vector<Fragment> process =new Vector<Fragment>();
		
		HashMap<Fragment,HashSet<Fragment>> dependencies = new HashMap<Fragment, HashSet<Fragment>>();
		
		Vector<Fragment> fragList=new Vector<Fragment>(fragDir.getListeFragment());
		HashMap<String,MMME> elemList=new HashMap<String,MMME>(elemDir.getMMMEList());
		
		while(!process.containsAll(getGeneratingFragments(fragList))){	
			for(Fragment f : getGeneratingFragments(fragList)){
				if(process.containsAll(findDependencies(f,elemList)) && !process.contains(f)){
						dependencies.put(f, suppressedTransitions(findDependencies(f,elemList), dependencies));
						process.add(f);	
				
				}
			}
		}
		
		if(Debug.isDebug())XMLProcessGenerator.writeProcess(dependencies);
		
		ProcessView.reloadGraph(dependencies);
		
		Debug.println("\n\t------------PROCESSUS----------\n");
		for(Fragment f : process){
			Debug.println(	 "Fragment : "+f.getId() 
							+" Stim : "+f.getCurrentStimulation()
							+" Process : "+f.currentProcess());
		}
		Debug.println("\t-------------------------------\n\n");
	}

	@Override
	public synchronized void run() {
		
		while(!stop){	
			try {
				wait(500);
				ProcessFinder.findProcess(fragDir, elemDir);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
}
